package main

import (
	"image"
	"fmt"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io/ioutil"
	"log"
	"math"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"github.com/signintech/gopdf"
)

func main() {
	if len(os.Args) < 2 {
		log.Fatal("请通过命令行参数指定目录，例如：pdfmerger.exe C:\\path\\to\\directory")
	}

	selectedDir := os.Args[1]
	log.Println("正在处理目录:", selectedDir)

	// 获取目录名作为 PDF 文件名
	dirName := filepath.Base(selectedDir)
	outputPath := filepath.Join(selectedDir, dirName+".pdf")
	log.Println("生成的 PDF 文件将保存为:", outputPath)

	subDirs, err := getSortedSubDirs(selectedDir)
	if err != nil {
		log.Fatal("获取子目录失败:", err)
	}

	log.Printf("找到 %d 个子目录\n", len(subDirs))

	pdf := gopdf.GoPdf{}
	pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})

	totalImages := 0
	for _, subDir := range subDirs {
		imageFiles, err := getSortedImageFiles(subDir)
		if err != nil {
			log.Printf("跳过目录 %s: %v\n", subDir, err)
			continue
		}
		totalImages += len(imageFiles)
	}

	log.Printf("总共找到 %d 张图片\n", totalImages)

	currentImage := 0
	for _, subDir := range subDirs {
		log.Println("正在处理子目录:", subDir)
		imageFiles, err := getSortedImageFiles(subDir)
		if err != nil {
			log.Printf("跳过目录 %s: %v\n", subDir, err)
			continue
		}

		for _, imgPath := range imageFiles {
			currentImage++
			progress := float64(currentImage) / float64(totalImages) * 100
			log.Printf("正在处理图片: %s (进度: %.2f%%)\n", imgPath, progress)

			if err := addImageToPDF(&pdf, imgPath); err != nil {
				log.Printf("跳过文件 %s: %v\n", imgPath, err)
			}
		}
	}

	log.Println("正在生成 PDF 文件:", outputPath)
	if err := pdf.WritePdf(outputPath); err != nil {
		log.Fatal("生成 PDF 失败:", err)
	}

	log.Println("PDF 已生成:", outputPath)
	log.Println("按 Enter 键退出...")
	fmt.Scanln() // 等待用户按 Enter 键
}

// 获取子目录并按自然顺序排序
func getSortedSubDirs(parentDir string) ([]string, error) {
	entries, err := ioutil.ReadDir(parentDir)
	if err != nil {
		return nil, err
	}

	var subDirs []string
	for _, e := range entries {
		if e.IsDir() {
			subDirs = append(subDirs, filepath.Join(parentDir, e.Name()))
		}
	}

	// 自然排序
	sort.Slice(subDirs, func(i, j int) bool {
		return naturalLess(subDirs[i], subDirs[j])
	})

	return subDirs, nil
}

// 获取图片文件并按自然顺序排序
func getSortedImageFiles(dir string) ([]string, error) {
	entries, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil, err
	}

	var files []string
	for _, e := range entries {
		if !e.IsDir() && isImageFile(e.Name()) {
			files = append(files, filepath.Join(dir, e.Name()))
		}
	}

	// 自然排序
	sort.Slice(files, func(i, j int) bool {
		return naturalLess(files[i], files[j])
	})

	return files, nil
}

// 判断文件是否为图片
func isImageFile(name string) bool {
	ext := strings.ToLower(filepath.Ext(name))
	return ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif"
}

// 添加图片到 PDF
func addImageToPDF(pdf *gopdf.GoPdf, path string) error {
	file, err := os.Open(path)
	if err != nil {
		return err
	}
	defer file.Close()

	img, _, err := image.Decode(file)
	if err != nil {
		return err
	}

	bounds := img.Bounds()
	imgW := float64(bounds.Dx())
	imgH := float64(bounds.Dy())

	// 添加新页面
	pdf.AddPage()

	// 计算缩放比例以适应A4页面
	pageW, pageH := 595.28, 841.89 // A4尺寸（单位：点）
	scaleW := pageW / imgW
	scaleH := pageH / imgH
	scale := math.Min(scaleW, scaleH)

	// 计算居中位置
	x := (pageW - imgW*scale) / 2
	y := (pageH - imgH*scale) / 2

	// 添加图片到PDF
	if err := pdf.Image(path, x, y, &gopdf.Rect{W: imgW * scale, H: imgH * scale}); err != nil {
		return err
	}

	return nil
}

// 自然排序比较函数
func naturalLess(a, b string) bool {
	re := regexp.MustCompile(`(\d+)|(\D+)`)
	aParts := re.FindAllString(a, -1)
	bParts := re.FindAllString(b, -1)

	for i := 0; i < len(aParts) && i < len(bParts); i++ {
		aPart := aParts[i]
		bPart := bParts[i]

		// 如果两部分都是数字，按数值比较
		aNum, aErr := strconv.Atoi(aPart)
		bNum, bErr := strconv.Atoi(bPart)
		if aErr == nil && bErr == nil {
			if aNum != bNum {
				return aNum < bNum
			}
		} else {
			// 否则按字符串比较
			if aPart != bPart {
				return aPart < bPart
			}
		}
	}

	// 如果前面的部分都相同，较短的字符串更小
	return len(aParts) < len(bParts)
}